Intrroduction
Recently i was experimenting with Stimulus as a light weight javascript library to use with django, and i found a great video course at Stimulus - Symfony Cast.
The problem
I had some values passed from django view to the html template via context and i wanted to access those values on javascript stimulus controller
Solution
Stimulus has a builtin method to do that, its called Stimulus Values, let us assume that we need to pass the django user email to javascript, first we need to create a stimulus controller on the html then we pass the user email as a value like this (I will assume that you have a working django setup with stimulus)
<div
data-controller="email-ctrl"
data-email-ctrl-user-email-value="{{ user.email }}"
>
...
</div>
Notice the name is important and follow this pattern data-{controller_name}-{value-name}-value
, the value name is written in the html as kebab-case
and will automatically transfered into camelCase
so user-email
will become userEmail
on the javascript side, in your stimuluse controller define the values that you are expecting and use it
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
static values = {
userEmail: { type: String, default: "" },
};
connect() {
console.log("Controller connected to: ", this.element);
// access the passed value
console.log(this.userEmailValue);
}
}
all good so far, but when i watched the video on the above mentioned course,I found that in Symfony PHP framework which use twig template engine, they have a nicer way Twig Function for defining the controller with its values, something similar to this
<div {{ stimulus_controller("email-ctrl" , { "user-email": user.email}) }}>
...
</div>
and i wondered if i can have something similar in django so i built a simple template tag for it
# <django_app>/templatetags/stimulus.py
import re
from django import template
register = template.Library()
def convert(name: str):
"""convert camelCase to kebab-case"""
return re.sub(r"(?<!^)(?=[A-Z])", "-", name).lower()
@register.simple_tag
def stimulus_controller(controller_name: str, **kwargs):
"""Render a Stimulus controller tag."""
stimulus_values = [
f"data-{controller_name}-{convert(k)}-value={v.strip()}"
for k, v in kwargs.items()
if v.strip() != ""
]
return f"data-controller={controller_name} {' '.join(stimulus_values)}"
then in your template use it like this
{% load stimulus %}
...
...
<div {% stimulus_controller 'email-ctrl' userEmail=user.email %} >
...
</div>
now when django render the template it will generate the same above html with data-
attrributes
isn't it beutiful :D